$Yachtum$ con AngularJS para EA

Imports

Para que el notebook funcione como es debido es necesario importar funciones de display del notebook y cargar las imágenes para mostrarlas cuando sea necesario.


In [1]:
import os
from IPython.display import HTML
from IPython.display import display_pretty, display_html, display_jpeg, display_png, display_json, display_latex, display_svg
from IPython.display import Image
from IPython.display import FileLink, FileLinks

In [2]:
%cd
app=Image(filename='AngularImg/App.png')
route=Image(filename='AngularImg/route.png')
controller=Image(filename='AngularImg/controller.png')
directive=Image(filename='AngularImg/directive.png')
search=Image(filename='AngularImg/search.png')


/home/ea

In [3]:
HTML("""<style>
div.warn {    
    background-color: #fcf2f2;
    border-color: #dFb5b4;
    border-left: 5px solid #dfb5b4;
    padding: 0.5em;
    }
div.tip {    
    background-color: #E0F8F7;
    border-color: #58FAF4;
    border-left: 5px solid #0B615E;
    padding: 0.5em;
    }
 </style> """+"""<div class=tip> Ahora ya se pueden usar tips</div>""")


Out[3]:
Ahora ya se pueden usar tips

1. Presentación del framework

AngularJS es un framework de desarrollo web basado en JavaScript e impulsado por Google que permite el desarrollo de aplicaciones web. Permite extender las funcionalidades de HTML5 de manera fácil y estructurada. En el siguiente link puedes acceder la guia del desarrollador de AngularJS, en la se exponen las funcionalidades principales del framework.

Hemos elegido Angular debido a su versatilidad, simplicidad y capacidad organizativa del código generado. Además nos ofrece control total sobre cómo distribuir la carga de trabajo entre el servidor y el usuario de la aplicación.


In [55]:
HTML('<iframe src="https://docs.angularjs.org/guide" width=1000 height=400></iframe>')


Out[55]:

1.2 Tutoriales

A continuación expondremos los tutoriales que se han utilizado como base a la aplicación desarrollada en este proyecto. El primer tutorial que utilizamos, Shaping up with AngularJS, es un curso sobre angular de Code School en el que se explica paso a paso como contruir una tienda de gemas. Es un curso que es posible realizar desde el navegador.

El segundo tutorial, es un ejemplo sobre cómo elaborar un catálogo de teléfonos que encontramos en la página de Angular. En él se explica cómo utilizar las funcionalidades básicas de Angular de una manera un tanto más convencional que en $Shaping$ $up$ $with$ $AngularJS$.

**Tip:** Es recomendable empezar por el tutorial de Code School. Es posible realizarlo online, y tendrás todo el material necesario para realizarlo a mano y no te tendrás que preocupar de configurar nada.

2. Estructura del proyecto

Todo el proyecto se encuentra dentro de la carpeta Yachtum de directorio personal. A continuación se detallarán los aspectos más relevantes de su contenido. Se dedicará un capítulo entero a la carpeta js, ya que en ella se encuentras las funcionalidades principales de AngularJS.

Tip: Para trabajar con AngularJS recomendamos el uso de Sublime Text, que ya esta configurado y listo para usarse en la máquina virtual ejecutando la siguiente celda.


In [16]:
%cd
%cd Sublime\ Text\ 2/
os.system("sudo ./sublime_text&")


/home/ea
/home/ea/Sublime Text 2
Out[16]:
0

2.1 Bower_components

Esta carpeta contiene las dependencias neccesarias para ejecutar la aplicación. En AngularJS las dependencias están gestionadas mediante Bower.

**Tip:** En el tutorial de phonecat-app se explica cómo se utiliza bower.

2.2 Css

Aquí se encuentras los css que utilizaremos para $Yachtum$. Podemos contar con unos css diseñados por María Vicente e implementados por Félix Sandoval que darán un aire profesional a nuestra aplicación.

2.3 Img

En esta carpeta se encuentran las imágenes utilizadas en $Yachtum$. Su estructura es la siguiente:


In [57]:
%cd
%cd Yachtum/app/img
!ls


/home/ea
/home/ea/Yachtum/app/img
banner-bottom.png  glyphicons-halflings.png	   Logo.png
barcos		   glyphicons-halflings-white.png  phones

2.4 JQuery

AngularJs funciona sobre JQuery, por lo que es necesario tenerlo instalado para que todo funcione correctamente.

2.5 Index.html

Este archivo, juntamente con app.js, será el núcleo de la aplicación. En él definiremos el esqueleto de nuestra página principal, importando las dependencias de nuestra aplicación y definiendo el cuerpo de la página como " div ng-view" para que se cargue allí toda nuestra aplicación. En nuestro caso, además cargaremos el menú de navegación fuera de la vista de la página porque queremos que tenga un comportamiento ajeno a ésta.

**Tip:** Evita al máximo llenar de código este archivo. Si estás programando bien deberías escribir el código en archivos separados y cargarlo desde directivas o mediante rutas.

2.6 Partials

En esta carpeta se incluye el código html de nuestra página separado en diferentes archivos. Encontramos una plantilla html para cada página y para cada directiva de nuestra aplicación.

**Tip:** Sublime Text ofrece una vista muy cómoda para navegar por el proyecto.

In [30]:
%cd
%cd Yachtum/app/partials/
!ls


/home/ea
/home/ea/Yachtum/app/partials
barco-detail.html	 bottom-homepage.html  primer barcopanels
barco-detail-pills.html  lista-compras.html    pruebas.html
barco-panels.html	 mis-compras.html      search-box.html
barco-review.html	 new-compras.html      search-list.html
barco-search.html	 phone-list.html       top-menu.html

3. La carpeta js

En esta carpeta es donde se centra la lógica de nuestra aplicación basada en JavaScript. De esta forma podemos separar el código html de la lógica de control en sus diferentes componentes de forma clara y estructurada.


In [31]:
%cd
%cd Yachtum/app/js/
!ls


/home/ea
/home/ea/Yachtum/app/js
animations.js  app.js  controllers.js  directives.js  filters.js  services.js

Tip: Cada archivo de la carpeta se corresponde con una característica esencial de AngularJS.

Vamos a aprovechar la estructura de la carpeta para explicar cada uno de los componentes básicos en los que se divide AngularJS. De esta forma aprenderemos de entrada a estructurar el código para que sea limpio y mantenible.

3.1 app.js

En este archivo es donde definimos la aplicación y los módulos que formarán parte de ella. Además, es aquí donde se definen las rutas de nuestra aplicación. Este archivo nos permite dividir la aplicación en módulos de forma que el código se pueda estructurar según los requerimientos del proyecto.

A continuación comentaremos los aspectos más importantes de este app.js:

3.1.1 Definición de la aplicación Angular

En las siguientes líneas se observa cómo se define nuestra aplicación. Definimos la variable YachtumApp, que será nuestra aplicación y le indicamos que cargue los módulos 'ngRoute','YachtumControllers' y 'YachtumDirectives'.

**Tip:** Para que los módulos se puedan importar correctamente los archivos donde están definidos deben cargarse en index.html.

In [33]:
app


Out[33]:
**Tip**: Esto que acabamos de hacer se llama Dependency Injection y en el link se ofrece una explicación detallada de su funcionamiento.

3.1.2 Rutas

Gracias al módulo $routeProvider podemos controlar cómo nuestra aplicación gestionará las rutas. En el ejemplo mostrado indicamos que cuando la ruta solicitada sea '/search' se cargará el archivo barco-search.html ubicado en /partials y cuya lógica de control estará definida en el controlador BarcoListCtrl.


In [35]:
route


Out[35]:

Tip: Puede que te interese echar un vistazo a la documentación de <a href"https://docs.angularjs.org/api/ngRoute/provider/$routeProvider"> routeProvider.</a>

3.2 controllers.js

Aquí es donde escribiremos la lógica de control de nuestras directivas y de los elementos que implementemos en las páginas html.

En AngularJS la lógica de la aplicación se separa del código html mediante el uso de **Controllers**. Un Controller es un módulo que agrupa un conjunto de funciones encargadas de una parte de la lógica de la aplicación.

En este ejemplo mostramos ComprasController, el controlador que se encargará de la gestión de las compras de la página. En primer lugar se puede observar cómo después de definir su nombre se inyectan las dependencias que el controlador utilizará. En este caso las dependencias serán scope , routeParams , $http. Para utilizarlas dentro del controlador primero se incluirán dentro del array y después se pasarán como parámetros de la función.

Dentro del controlador definiremos las funciones que realizará. En este caso realizará una petición http y asignará la respuesta a la variable user. Además, se definirá una segunda variable que contendrá las compras del usuario cargado.

También se ha definido una función addCompra en la que se guardará la compra pasada por parámetro y se añadirá al $scope.


In [36]:
controller


Out[36]:
**Tip**: Los controles técnicamente pueden definirse en varios sitios, pero se recomienda agruparlos todos en un mismo módulo.

3.3 directives.js

En este archivo es dónde definimos las directivas de nuestra aplicación. Las directivas son la forma que tiene AngularJS para extender las funcionalidades de HTML. Las directivas sirven para extender la sintaxis de HTML5 con los componentes programados con AngularJS.

En este ejemplo podemos observar la directiva listaCompras que se encargará de mostrar las compras de un usuario. Para lograrlo primero definimos que nuestra directiva se utilizará como un elemento HTML mediante el comando restrict:'E', en la segunda linea de código definimos el archivo en el que está definido el código HTML de nuestra directiva y en la tercera indicamos que la lógica de la directiva vendrá definida por ComprasController.


In [37]:
directive


Out[37]:

3.4 filters.js

En este archivo definimos los filtros personalizados.

3.5 services.js


In [57]:

3.4 animations.js


In [57]:

Esta aplicación es un ejemplo del tipo de aplicaciones para las que AngularJs es ideal. Yachtum es un portal web de alquiler de barcos en las que un cliente puede buscar un barco para alguilar seleccionando unas fechas para su viaje y un puerto desde el que embarcarse y se le mostraran una lista de embarcaciones que tendrá a su disposición para alquilar.

**Tip:** Ejecuta las siguientes celdas para empezar a trabajar rápidamente. Le primera ejecutará un servidor *node* desde el que servir la web y la segunda cargará el editor de textos.

In [4]:
%cd
%cd Yachtum
os.system('konsole&')
#escribe en la consola:
#npm start


/home/ea
/home/ea/Yachtum
Out[4]:
0

In [5]:
%cd
%cd Sublime\ Text\ 2/
os.system("sudo ./sublime_text&")


/home/ea
/home/ea/Sublime Text 2
Out[5]:
0

In [18]:
HTML('<iframe src="http://localhost:8000/app/" width=1200 height=450></iframe>')


Out[18]:

4.1 Página principal de búsquedas

Desde la página principal se puede realizar una búsqueda de barcos disponibles. Para poder realizar una búsqueda es necesario introducir un puerto de origen, una fecha de salida y una fecha de llegada.

Una vez realizada la primera búsqueda se mostraran los resultados obtenidos en una lista. Es posible obtener una vista detallada de un barco haciendo click sobre su nombre. Al hacer click sobre el botón "embárcate" se procederá a la reserva del barco.

4.1 Vista en detalle del barco

En esta vista se muestran las características del barco seleccionado y es posible ver los comentarios dejados por los usuarios y dejar comentarios propios.

5. Tutorial 1: Creando un panel de búsquedas

El panel de búsqueda es una directiva que nos permite implementar el panel con el que realizar las búsquedas de embarcaciones disponibles. A continuación explicaremos todo el proceso que hay que llevar a cabo para implementar este elmento utilizando AngularJS.


In [5]:
HTML("""<div class="l-main" ng-controller="BarcoListCtrl as listCtrl">
    <div class="l-main-h">
        <div class="l-submain"  style="background: #FFF url('img/slider2.png') center; ">
          <div class="l-submain-h g-html">
                <div class="container-fluid">
                    <div class="container-fluid">
                        <div class="col-md-4">
                            <!--Sidebar content-->               
                        </div>
                        <div class="col-md-4" >    
                        <h4 ng-show="listCtrl.searchClicked(11)">Encuentre su barco perfecto y disfrute de sus ventajas</h4>
                        <h4 ng-show="listCtrl.searchClicked(10)">Resultados de la búsqueda para</h4>
                        <form name="reviewForm" ng-submit="listCtrl.clickSearchb(10)">
                            <div class="row">
                               <div class="col-md-12"> 
                                    <div ng-show="listCtrl.searchClicked(12)">Selecciona un puerto:</div>
                                    <div ng-show="listCtrl.searchClicked(12)">Puerto seleccionado:</div>
                                    <select ng-options="puerto for puerto in listaPuertos" ng-model="barco.puerto" required>     
                                        <option value="" >-- Elige tu puerto de origen --</option>
                                    </select>
                                </div>
                            </div>

                            <div class="g-cols">   
                                <div class="one-half">  
                                    <p>fecha de salida <input type="date" ng-model="dstart" min="{{listCtrl.today()| date:'mm/dd/yyyy'}}" required> </p>
                                </div>
                                <div class="one-half">  
                                    <p>fecha de llegada <input type="date" min="{{dstart}}" required="{{dstart}}" ng-model="dend" required></p>
                                </div>
                            </div>
                            
                            <div class="row">
                                <div class="col-md-7">          
                                    <!--Embarcación:-->
                                    <select placeholder="Selecciona un puerto" ng-options="tipoBarco for puerto in listaTiposBarco" ng-model="tiposBarco" >     
                                    
                                    <option value="">--Elige el tipo de Barco--</option>
                                    </select>
                                </div>
                                <div class="col-md-4">
                                    <input type="submit" class="btn btn-primary pull-right" value="Buscar" />
                                </div>
                            </div>      
                        <form>
                        </div>
                    </div>                                      
                </div>
            </div>
        </div>
        
    </div>
</div>""")


Out[5]:

Encuentre su barco perfecto y disfrute de sus ventajas

Resultados de la búsqueda para

Selecciona un puerto:
Puerto seleccionado:

fecha de salida

fecha de llegada

5.1 Plantilla HTML

En este paso definiremos el aspecto de nuestra directiva.

En primer lugar crearemos un nuevo archivo que contendrá el código HTML que se utilizará para representar el panel de búsquedas. En este caso lo llamaremos search-box.html y en su interior escribiremos lo siguiente:

Encuentre su barco perfecto y disfrute de sus ventajas

Resultados de la búsqueda para

Selecciona un puerto:
Puerto seleccionado:

fecha de salida

fecha de llegada

Tip: La lógica de control básicamente estará (salvo algunas palabras reservadas) incluida en las tags *ng-** y dentro de los símbolos {{ }}

Tal como se puede observar, toda la logica de la aplicación esta incluida en directivas del tipo ng-something, por lo que queda separada del código html utilizado para mostrar la directiva. Algunas de las directivas que aparecen en la plantilla son:

ng-model asigna el valor introducido por el usuario a la variable dstart. min indica que el valor mínimo del formulario tiene que ser igual al día de hoy. Esto se consigue utilizando la función today() del controlador de la lista e indicándole mediante un filtro que se trata de una fecha. El campo required indica que este campo del formulario es obligatorio.

Selecciona un puerto:

**ng-show** indica que el elemento se mostrará siempre que se cumpla la condición indicada. En este caso es que la función searchClicked() de listCtrl retorne true al pasarle por parámetro 12.

5.2 Controlador del search-panel

Aquí se puede ver cómo se define el controlador del panel de búsqueda. Mediante la notación {{variable.atributo}}. Así se puede acceder a las variables definidas en el **scope** desde la plantilla html.

yachtumControllers.controller('BarcoListCtrl',['$scope','$http', function($scope,$http) { $http.get('barcos/barcos.json').success(function(data){ $scope.barcos=data; }); $http.get('barcos/listaPuertos.json').success(function(data) { $scope.listaPuertos = data; }); $http.get('barcos/' + 'velero' + '.json').success(function(data) { $scope.barcosd = data; }); $scope.orderProp="age"; $scope.clicksearch=11; $scope.orderBarcos = 'porder'; $scope.reverse=false; this.today=function(){ return new Date(); } $scope.end = new Date(); $scope.minStartDate = $scope.end; //fixed date <--! esta es la lógica que se usa para controlar las pestañas--> this.clickSearchb= function(setClickSearch){ $scope.clicksearch=setClickSearch; }; this.searchClicked=function(checkTab){ return $scope.clicksearch===checkTab; }; }]);

5.3 Definiendo la directiva

Una vez se tiene el código html y el controlador listo llega el momento de definir cómo van a iteractuar con el usuario mediante la creación de una directiva. En este caso la directiva creada es la siguiente:


In [67]:
search


Out[67]:

Aquí se indica que la directiva se podrá llamar como un elemento desde una plantilla html:

Y que al hacerlo se presentará la plantilla search-box.html. No se hace ninguna mención explícita al controlador porque se define in situ en la plantilla.

Los filtros son los elementos de Angular que permiten dar formato a las expresiones que serán mostradas al usuario. Existen diversos filtros predefinidos y en caso de necesitarlo el usuario puede crear sus propios filtros.

**Tip:** Los filtros que te conviene tener a mano son:
**Filtro** **Útil para**
Date Si trabajas con fechas éste es tu filtro.
Currency Dinero. Permite utilizar cualquier singno para designar las cantidades.
Filter Filtro multiusos. Con él puedes filtrar listas, seleccionar parámetros y utilizar el parámetro introducido como filtro para mostrar resultados.
OrderBy Sirve para ordenar listas de elementos. Su uso es {{ orderBy_expression | orderBy : expression : reverse}} y permite indicar elemento sobre el que ordenar y orden ascendente o descendente.

5.4.1 Usando un solo filtro.

En este ejemplo el filtro utilizado es Date. Con su utilización pretendemos asegurar que el dato introducido se corresponde con una fecha, y al asignarle el formato 'mm/dd/yyyy' nos aseguramos de que no habrá problemas a la hora de comparar la fecha con la elegida por el usuario.

| date:'mm/dd/yyyy'

Un ejemplo más interesante del uso de filtros sería el incorporado en la directiva de la lista de barcos. En este archivo ubicado en search-list.html encontramos la siguiente línea de código:

5.4.2 Combinando filtros

5.4.2.1 La directiva ng-repeat

En esta celda podemos ver la aplicación combinada de dos filtros para realizar busquedas en una lista de elementos. Mediante la directiva **ng-repeat** indicamos a la aplicación que ejecute el código de dentro del elemento section una vez para cada barco, creando una variable barco que contendra cada uno de los elementos de la lista de objetos barcos.

Atención: la variable barcos estará definida en el controlador como $scope.barcos. De cómo esta variable toma los valores se encarga el controlador. Tú asume que tienes lo que necesitas.

**Tip:** Utiliza ng-repeat de forma análoga a un bucle for pero para código HTML5.
5.4.2.2 Directiva filter

Mediante la estructura |filter:barco.puerto indicamos a Angular que de la lista de elementos proporcionada por ng-repeat solo escoja las que tengan algún elemento que coincida con barco.puerto.

Atención: barco.puerto hace referencia al puerto seleccionado en el formulario de búsqueda. En este caso se comparará el resultado del formulario con el campo barco.puerto de cada barco de la lista.

5.4.2.3 Directiva orderBy

|orderBy:orderBarcos:reverse Indica a la aplicación que ordene los resultados de búsqueda segun la variable orderBarcos, y mediante reverse indicamos que se tenga en cuenta el orden de la lista mediante una variable booleana que indicará orden ascendente o descendente.

Tip: Puedes asignar valores a reverse y a la variable que utilices para ordenar de forma independiente, separando en el código los criterios de selección de orden y el de selección de variable por la que ordenar.

5.4.2.4 Combinando diferentes filtros sobre una misma lista

En este ejemplo hemos visto como concurren diferentes filtros (que además dependen de variables diferentes) sobre una misma expresión. De esta manera podemos hacer que la lista de resultado sea filtrada por las diferentes opciones del formulario y además podamos gestionar de manera independiente como se muestran los resultados filtrador.

Además, sería posible añadir más filtros separándolos por el símbolo |.

6. Futuras versiones

Este tutorial no es más que una pequeña muestra de lo que puede ofrecer AngularJS como framework de programación de aplicaciones web. Existen todavía un gran número de aspectos del framework que no se han analizo, y que podrían dar lugar a futuros tutoriales.

Entre estos temas destacan: Los servicios, La implementación de una basde de datos con NodeJS o la creación de animaciones y filtros personalizados.

Este tutorial y los que se realicen posteriormente estarán disponibles de forma gratuita en el repositorio de Github de Guillem Duran.


In [ ]: